/**************************************************************
 *
 * userprog/ksyscall.h
 *
 * Kernel interface for systemcalls 
 *
 * by Marcus Voelp  (c) Universitaet Karlsruhe
 *
 **************************************************************/

#ifndef __USERPROG_KSYSCALL_H__ 
#define __USERPROG_KSYSCALL_H__ 

#include "kernel.h"
#include <stdio.h>
#include <string>



void SysHalt()
{
  kernel->interrupt->Halt();
}


int SysAdd(int op1, int op2)
{
  return op1 + op2;
}

/*
 * Get the string from the register.
 */
void SysGetchar(char *addr, char *string)
{
	do {
			kernel->machine->ReadMem((int)addr++, 1, (int *)string++);

	} while (*(string-1) != '\0');
	
}

/*
 * Print the string on the screen.
 */
void SysPrint(char *string)
{
	char ch;
	do {
			kernel->machine->ReadMem((int)string++, 1, (int *)&ch);
			kernel->synchConsoleOut->PutChar(ch);
			//printf("%c", ch);
	} while (ch != '\0');

}

/*
 * Print the number on the screen.
 */
void SysPrintNum(int num)
{	
	int i;
	char cnum[16];
	i = 0;

	sprintf(cnum, "%d", num);
	do{
		kernel->synchConsoleOut->PutChar(cnum[i++]);
	} while(cnum[i] != '\0');

}

/* 
 * Write "size" bytes from "buffer" to the open file. 
 * Return the number of bytes actually read on success.
 * On failure, a negative error code is returned.
 */
int SysWrite(char *buffer, int size, OpenFileId id)
{
    int result;

    if (id == ConsoleOutput)
    {
        result = size;    
		char ch;
    	do {
    		kernel->machine->ReadMem((int)buffer++, 1, (int *)&ch);
    		kernel->synchConsoleOut->PutChar(ch);
    	} while ((ch != '\0') && (--size != 0));
    }

    return result;
}

/* 
 * Read "size" bytes from the open file into "buffer".  
 * Return the number of bytes actually read -- if the open file isn't
 * long enough, or if it is an I/O device, and there aren't enough 
 * characters to read, return whatever is available (for I/O devices, 
 * you should always wait until you can return at least one character).
 */
int SysRead(char *buffer, int size, OpenFileId id)
{
    int result;

    if (id == ConsoleInput)
    {
        result = size;
		char ch;
        do {
            ch = kernel->synchConsoleIn->GetChar();
			kernel->machine->WriteMem((int)buffer++, 1, ch);
            //size--;cout<<size;
        } while ((ch != '\0') && (--size != 0));
    }

    return result;
}

/* 
 * Copy the Nachos file1 to file2, if there is no a file named "file2" 
 * we should create it first.
 * Return 1 on success, negative error code on failure
 */
int SysCopy(char *file1, char *file2)
{
	cout << "System call for copy!" << endl;
	cout << "the file1 name is " << file1 << endl;
	cout << "the file2 name is " << file2 << endl;

	return 1;
}

/* 
 * Append the Nachos file1 to the end of file2, if there is no a file named "file2" 
 * we should create it first.
 * Return 1 on success, negative error code on failure
 */
int SysAppend(char *file1, char *file2)
{
	cout << "System call for append!" << endl;

	return 1;
}

/* 
 * Echo the comment on the screen, and then turn to the new line.
 */
void SysEcho(char *comment)
{
//	cout << "System call for echo!" << endl;
	SysPrint(comment);
	cout << endl;
}

/* 
 * Create a Nachos file, with name "name"
 * Note: Create does not open the file.  
 * Return 1 on success, negative error code on failure 
 */
int SysCreate(char *name)
{
	cout << "System call for touch!" << endl;
	kernel->fileSystem->CreateFile(name, 10);
	return 1;
}

/* 
 * Move the file (or dirctory) form path1 to path2.
 * Return 1 on success, negative error code on failure 
 */
int SysMove(char *path1, char *path2)
{
	cout << "System call for move!" << endl;
	
	return 1;
}

/* 
 * Remove a Nachos file, with name "name".
 * Return 1 on success, negative error code on failure 
 */
int SysRemove(char *name)
{
	cout << "System call for rm!" << endl;
	kernel->fileSystem->Remove(name);
	return 1;
}

/* 
 * Create the file directory.
 * Return 1 on success, negative error code on failure 
 */
int SysMkdir(char *name)
{
	cout << "System call for mkdir!" << endl;
	cout<<"name = "<<name<<endl;
	kernel->fileSystem->CreateDirectory(name);
	return 1;
}

/* 
 * Remove the file directory.
 * Return 1 on success, negative error code on failure 
 */
int SysRmdir(char *name)
{
	cout << "System call for rmdir!" << endl;
	kernel->fileSystem->Remove(name);
	return 1;
}

/* 
 * Change the file directory.
 * Return 1 on success, negative error code on failure 
 */
int SysChangedir(char *name)
{
	cout << "System call for cd!" << endl;
	kernel->fileSystem->ChangeDirectory(name);
	return 1;
}

/* 
 * List the file and content under the dirctory.
 * Return 1 on success, negative error code on failure 
 */
int SysListdir(char *name)
{
	cout << "System call for ls!" << endl;
	kernel->fileSystem->List();
	return 1;
}

/* 
 * Print the work directory.
 */
void SysPwd()
{
	cout << "System call for pwd!" << endl;
}

//----------------------------------------------------------------------
// IncrePC
//  If you are handling a system call, don't forget to increment the pc
//  before returning. (Or else you'll loop making the same system call forever!)
//----------------------------------------------------------------------
void IncrePC()
{
    /* set previous programm counter (debugging only)*/
    kernel->machine->WriteRegister(PrevPCReg, kernel->machine->ReadRegister(PCReg));

    /* set programm counter to next instruction (all Instructions are 4 byte wide)*/
    kernel->machine->WriteRegister(PCReg, kernel->machine->ReadRegister(PCReg) + 4);

    /* set next programm counter for brach execution */
    kernel->machine->WriteRegister(NextPCReg, kernel->machine->ReadRegister(PCReg)+4);
}


//----------------------------------------------------------------------
// StartProcess
//  Create an address space, and then run a user program according to 
//  the full filename.
//----------------------------------------------------------------------
void
StartProcess(char *filename)
{
	kernel->spaceList->Front()->SaveReg();
//    OpenFile *executable = kernel->fileSystem->Open(filename);
    AddrSpace *space;
//    if (executable == NULL) {
//	printf("Unable to open file %s\n", filename);
//	return;
//    }
    space = new AddrSpace();
//    delete executable;			// close file
	if (space->Load(filename)) {  // load the program into the space
		space->Execute();              // run the program
		ASSERTNOTREACHED();            // Execute never returns
    }

    ASSERT(FALSE);			// machine->Run never returns;
					// the address space exits
				// by doing the syscall "exit"
}



#endif /* ! __USERPROG_KSYSCALL_H__ */
